#ifndef __MQ_QUEUE_HPP__
#define __MQ_QUEUE_HPP__

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <mutex>
#include <sstream>
#include "../mq_comm/mq_msg.pb.h"
#include "../mq_comm/helper.hpp"

namespace mq
{
    /*
        队列信息类
        这里阐述的是队列的属性信息,不是实际队列
    */
    struct MsgQueue
    {
        using ptr=std::shared_ptr<MsgQueue>;
        std::string name;//队列名称
        bool durable;//队列是否持久化标志
        bool exclusive;//队列是否被独占标志
        bool auto_delete;//队列是否开启自动删除标志
        //std::unordered_map<std::string,std::string> args;//其他参数
        google::protobuf::Map<std::string,std::string> args;//其他参数

        MsgQueue()=default;
        MsgQueue(const std::string& _name,bool _durable,
                bool _exclusive,bool _auto_delete,
                const google::protobuf::Map<std::string,std::string>& _args)
        :name(_name),durable(_durable),exclusive(_exclusive),auto_delete(_auto_delete),args(_args){}

        /*序列化其他参数，形如key=val&key=val&*/
        std::string getArgs()
        {
            std::stringstream ss;
            for(auto& iter:args)
            {
                ss<<iter.first<<"="<<iter.second<<"&";
            }
            return ss.str();
        }

        /*反序列化其他参数，将形如key=val&key=val&的字符串反序列化为args*/
        void setArgs(const std::string &str_args)
        {
            std::vector<std::string> vs;
            StrHelper::split(str_args,"&",&vs);
            for(auto& str:vs)
            {
                size_t pos=str.find("=");
                std::string key=str.substr(0,pos);
                std::string val=str.substr(pos+1);
                args[key]=val;
            }
        }
    };

    using QueueMap=std::unordered_map<std::string,MsgQueue::ptr>;
    /*操作队列数据库表类*/
    class MsgQueueMapper
    {
    public:
        MsgQueueMapper(const std::string& filename):_sql_helper(filename)
        {
            //考虑到传入的路径下的file的父目录可能不存在,需要先创建
            std::string parentPath=FileHelper::parentDirectory(filename);
            FileHelper::createDirectory(parentPath);
            //打开数据库，创建数据库表文件
            assert(_sql_helper.open());
            createTable();
        }

        /*创建数据库表文件*/
        void createTable()
        {
            #define CREATE_QUEUE "create table if not exists queue_table(\
            name varchar(32) primary key,\
            durable int,\
            exclusive int,\
            auto_delete int,\
            args varchar(128));"

            assert(_sql_helper.exec(CREATE_QUEUE,nullptr,nullptr));
        }

        /*删除数据库表文件*/
        void removeTable()
        {
            #define DROP_QUEUE "drop table if exists queue_table;"
            _sql_helper.exec(DROP_QUEUE,nullptr,nullptr);
        }

        // std::string name;//队列名称
        // bool durable;//队列是否持久化标志
        // bool exclusive;//队列是否被独占标志
        // bool auto_delete;//队列是否开启自动删除标志
        // std::unordered_map<std::string,std::string> args;//其他参数

        /*向数据库表文件中插入数据*/
        bool insert(MsgQueue::ptr& queue)
        {
            std::stringstream ss;
            ss<<"insert into queue_table values(";
            ss<<"'"<<queue->name<<"', ";
            ss<<queue->durable<<", ";
            ss<<queue->exclusive<<", ";
            ss<<queue->auto_delete<<", ";
            ss<<"'"<<queue->getArgs()<<"');";
            return _sql_helper.exec(ss.str(),nullptr,nullptr);
        }

        /*根据队列名称删除数据库表中的指定内容*/
        void remove(const std::string& name)
        {
            std::stringstream ss;
            ss<<"delete from queue_table where name=";
            ss<<"'"<<name<<"';";
            _sql_helper.exec(ss.str(),nullptr,nullptr);
        }

        

        /*从数据库文件中查找所有数据,并恢复返回*/
        QueueMap recovery()
        {
            QueueMap result;
            const std::string query="select name,durable,exclusive,auto_delete,args from queue_table;";
            _sql_helper.exec(query,selectCallback,&result);
            return result;
        }
    private:
        static int selectCallback(void* args, int col, char** rows, char** fields)
        {
            QueueMap* result=(QueueMap*)args;
            auto queue=std::make_shared<MsgQueue>();
            queue->name=rows[0];
            queue->durable=(bool)std::stoi(rows[1]);
            queue->exclusive=(bool)std::stoi(rows[2]);
            queue->auto_delete=(bool)std::stoi(rows[3]);
            if(rows[4]) queue->setArgs(rows[4]);
            result->insert(std::make_pair(queue->name,queue));
            return 0;
        }

    private:
        SqliteHelper _sql_helper;
    };

    /*管理队列类*/
    class MsgQueueManager
    {
    public:
        using ptr=std::shared_ptr<MsgQueueManager>;
        MsgQueueManager(const std::string& filename):_mapper(filename)
        {
            _msg_queues=_mapper.recovery();
        }

        /*声明队列*/
        bool declareQueue(const std::string& name,
                        bool durable,
                        bool exclusive,
                        bool auto_delete,
                        const google::protobuf::Map<std::string,std::string>& args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto iter=_msg_queues.find(name);
            if(iter!=_msg_queues.end()) return true;
            auto queue=std::make_shared<MsgQueue>(name,durable,exclusive,auto_delete,args);
            if(durable==true)
            {
                bool ret=_mapper.insert(queue);
                if(ret==false) return false;
            }
            _msg_queues.insert(std::make_pair(name,queue));
            return true;
        }

        /*根据队列名称删除指定队列信息*/
        void deleteQueue(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto iter=_msg_queues.find(name);
            if(iter==_msg_queues.end()) return;
            if(iter->second->durable==true)
            {
                _mapper.remove(name);
            }
            _msg_queues.erase(name);
            return;
        }
        
        /*根据队列名称获取指定队列信息*/
        MsgQueue::ptr selectQueue(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto iter=_msg_queues.find(name);
            if(iter==_msg_queues.end()) return MsgQueue::ptr();
            return iter->second;
        }

        /*获取所有队列信息*/
        QueueMap allQueues()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _msg_queues;
        }

        /*根据队列名称判断队列是否存在*/
        bool exists(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto iter=_msg_queues.find(name);
            if(iter==_msg_queues.end()) return false;
            return true;
        }

        /*获取已有的队列数量*/
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _msg_queues.size();
        }

        /*清除队列所有信息*/
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();
            _msg_queues.clear();
        }
    private:
        std::mutex _mutex;//互斥锁
        MsgQueueMapper _mapper;//操作数据库表对象
        QueueMap _msg_queues;//内存存储队列信息
    };
}
#endif